﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using Mota.XMLControls;

namespace Mota.EditModule
{
    public partial class EditForm : DevExpress.XtraEditors.XtraForm
    {
        private static int tabIndex = int.MaxValue;
        public static int NextTabIndex
        {
            get
            {
                if(tabIndex<1)
                    tabIndex = int.MaxValue;
                return tabIndex--;
            }
        }


        // TODO: Add list of opened editForms to prevent recursion
        private static IInfoModuleInitiator infoModule = null;
        // controls with datasource
        private Dictionary<string, GuiControl> namedControls = new Dictionary<string, GuiControl>();
        private Dictionary<string, GuiControl> dataSourceControls = new Dictionary<string, GuiControl>();
        // main control and his dependants
        private Dictionary<GuiControl, List<Dependence>> mainToDependants = new Dictionary<GuiControl, List<Dependence>>();
        // dependant to mains
        private Dictionary<GuiControl, List<Dependence>> dependantToMains = new Dictionary<GuiControl, List<Dependence>>();
        // Dictionary with configs data
        private Dictionary<String, String> configs = null;
        // Defalut values from user 
        private Dictionary<string, object> overrideDefaults = null;
        // Fill form with data visitor
        private EditFormGuiVisitor gvisitor;

        // Collect form data visitior
        private EditFormCollectDataVisitor dataCollector;
        // Validator form visitior
        private EditFormIsValidVisitor currentValidator;

        // Root layer for my visual decorators
        private GuiControl rootGui = null;

        // Current edited record id
        private String id = null;

        private BindingSource binding = null;

        // Edit mode
        private EditFormMode editMode;
        // Object prototype
        private ObjectPrototype prototype = null;
        // ConnectionConfigs
        private ConnectionConfigs connectionConfig;
        
        public String Id
        {
            get 
            {
                return id;
            }
        }

        private EditFormGuiVisitor GuiVisitor
        {
            get
            {
                // Check edit mode for choosing correct visitor
                switch(EditMode)
                {
                    case (EditFormMode.Copy):
                    case (EditFormMode.Update):
                        gvisitor = new EditFormGuiVisitor(connectionConfig, this.prototype.GetCompatibleDataTable(), out binding);
                        gvisitor.SetValue(configs["XmlIU"], this.Id);                                     
                        break;
                    case (EditFormMode.Insert):
                        gvisitor = new EditFormGuiVisitor(connectionConfig,this.prototype.GetCompatibleDataTable(),out binding);
                        gvisitor.SetValue(configs["XmlIU"], String.Empty);
                        gvisitor.OverrideDefaultValues(overrideDefaults);
                        break;
                }
                return gvisitor;
            }
        }

        private Dictionary<string,object> CurrentData
        {
            get
            {
                
                dataCollector = new EditFormCollectDataVisitor(this.binding);
                this.rootGui.Accept(dataCollector);

                return dataCollector.CollectedList;
            }
        }

        private EditFormMode EditMode
        {
            get 
            {
                return this.editMode;
            }
            set
            {
                this.editMode = value;
                btnOk.Visible = true;

                // Change ok button text
                switch(editMode)
                {
                    case (EditFormMode.Copy):
                        btnOk.Text = Resources.GetString("Copy");
                        break;
                    case (EditFormMode.Insert):
                        btnOk.Text = Resources.GetString("Insert");
                        break;
                    case (EditFormMode.Update):
                        btnOk.Text = Resources.GetString("Update");
                        break;
                    default:
                        btnOk.Visible = false;
                        break;
                }
            }
        }

        static EditForm()
        {
            GuiBuilder.SetGuiFactory(new DXGuiFactory());
        }
        private EditForm()
        {

            InitializeComponent();
            // setup use DX controls by default
            this.EditMode = EditFormMode.None;
            this.btnOk.Enabled = false;
        }
        public void OverrideDefaults(Dictionary<string, object> userDefaultValues)
        {
            if (userDefaultValues == null)
                throw new ArgumentNullException(Resources.GetString("userDefaultValues can not be null."));

            overrideDefaults = userDefaultValues;
        }
        
        // static method to build and show dialog
        public static DialogResult ShowDialog(ConnectionConfigs configs, EditFormMode editMode, ref String inOutId,Dictionary<string,object> overrideValues = null)
        {
            
            if (editMode == EditFormMode.Delete)
            {
                // if user really want to remove record 
                if(MessageBox.Show(Resources.GetString("Are you really want to remove the record?"),
                    Resources.GetString("Removing the record"),MessageBoxButtons.OKCancel)==DialogResult.OK)
                {
                    // get view configuration by viewName
                    ViewConfig vc = Model.GetViewConfig(configs);
                    XDocument xdc = XDocument.Parse(vc.XmlConfig);

                    var procD = xdc.Elements(ConfigConstants.Root)
                                   .Elements(ConfigConstants.Configs)
                                   .Elements("ProcD")
                                   .Where(el => !el.IsEmpty && !el.HasElements)
                                   .FirstOrDefault();

                    if (procD != null)
                    {
                        SqlParameterCollection procResult =
                                Model.GetProcResult(
                                        configs,
                                        procD.Value,
                                        new Parameter[]{
                                            new Parameter(){
                                                Key = "@ID",
                                                Value = inOutId
                                            }
                                        }
                                    );
                        // return dialog result based on procedure result
                        if (procResult != null)
                        {
                            return DialogResult.OK;
                        }
                    }
                    else
                        throw new NullReferenceException(Resources.GetString("Delete procedure not defined for {0}", configs.ViewName));

                    // if cant find procedure for deletion return abort dialog result
                    return DialogResult.Abort;
                }
                else // if user cancel deletion
                    return DialogResult.Cancel;
            }
            else
            {
                // upate, insert or copy mode section
                // create edit form and show like dialog
                using (EditForm ef = new EditForm(configs, editMode, ref inOutId,overrideValues))
                {
                    DialogResult result = ef.ShowDialog();
                    //Assign received id to ref parameter inOutId
                    if (result == DialogResult.OK)
                        inOutId = ef.Id;

                    return result;
                }
            }

        }
        public static void SetInfoModuleInitiator(IInfoModuleInitiator initiator)
        {
            infoModule = initiator;
        }
        private EditForm(ConnectionConfigs conConfigs, EditFormMode editMode,ref String inOutId,Dictionary<string,object> overrideValues = null)
            : this()
        {
            try
            {
                if (editMode!=EditFormMode.Insert && String.IsNullOrEmpty(inOutId))
                    throw new ArgumentNullException(Resources.GetString("Id value can not be null or empty."));

                overrideDefaults = overrideValues;
                EditMode = editMode;
                connectionConfig = conConfigs;
                id = inOutId;
                // Start building presentation
                var buildSuccessful = true;
                ViewConfig vc = Model.GetViewConfig(connectionConfig);
            
                XDocument xdc = XDocument.Parse(vc.XmlConfig);  
                XElement root = xdc.Element(ConfigConstants.Root);
                if (root != null)
                {
                    buildSuccessful = parseGlobalConfigs(root.Element(ConfigConstants.Configs))&&
                                      buildVisualFormAndPrototype(root.Element(ConfigConstants.EditModule));
                    parseEditModuleFormConfigs(root.Element(ConfigConstants.EditModule));
                    parseDependencies(root.Element(ConfigConstants.EditModule));
                }
            }
            catch (Exception ex)
            {
                ex.LogError("D654ED2A-11FE-464D-8C4A-BD03458095F4");
                throw;
            }
        }

        private void parseDependencies(XElement editModuleSection)
        {
            try
            {

                if (editModuleSection == null)
                    return;
                var dependenciesSection = editModuleSection.Element(ConfigConstants.Dependencies);
                if (dependenciesSection == null)
                    return;
                foreach (var dep in dependenciesSection.Elements("Dependence"))
                {
                    string mainControlName = dep.Attribute("ChangedControl").Value,
                           childControlName = dep.Attribute("DependedControl").Value,
                           dependedFieldName = dep.Attribute("DependedField").Value;
                    if (dataSourceControls.ContainsKey(childControlName) && namedControls.ContainsKey(mainControlName))
                    {
                        var childControl = dataSourceControls[childControlName];
                        var mainControl = namedControls[mainControlName];
                        if (!(childControl is IDatasourceObject)
                            || (!childControl.XmlAttributes.ContainsKey("_Fields"))
                            || (!childControl.XmlAttributes["_Fields"]
                                                .ToLower()
                                                .Split(',')
                                                .Contains(dependedFieldName.ToLower())))
                            continue;
                        // If all checks correct
                        // Add dependant to mainToDependants dictionary
                        if (!mainToDependants.ContainsKey(mainControl))
                            mainToDependants[mainControl] = new List<Dependence>();
                        var controlChilds = mainToDependants[mainControl];
                        if (!controlChilds.Any(el => el.Control == childControl))
                        {
                            controlChilds.Add(new Dependence()
                            {
                                Control = childControl,
                                DependentField = dependedFieldName
                            });
                        }
                        // Add main to dependantToMains dictionary
                        if (!dependantToMains.ContainsKey(childControl))
                            dependantToMains[childControl] = new List<Dependence>();
                        childControl.AddMain(dependedFieldName, mainControl);
                        var controlMains = dependantToMains[childControl];
                        if (!controlMains.Any(el => el.Control == mainControl))
                        {
                            controlMains.Add(new Dependence()
                            {
                                Control = mainControl,
                                DependentField = dependedFieldName
                            });
                        }
                        mainControl.OnChange += mainControl_OnChange;
                    }
                }
            }
            catch(Exception ex)
            {
                ex.LogError("C8DBBA6C-13BD-42F6-BA5B-81A926241546");
                throw;
            }
        }

        void mainControl_OnChange(object sender, EventArgs e)
        {
            if (sender is GuiControl)
            {
                var mainControl = sender as GuiControl;
                List<Dependence> controlChilds = mainToDependants[mainControl];
                foreach (var dep in controlChilds)
                {
                    GuiControl guiChildCtrl = dep.Control;
                    if (guiChildCtrl.Binding is BindingSource)
                    {
                        (guiChildCtrl as IDatasourceObject).Refresh(connectionConfig,binding);
                        //DataSet childDataSet = ((guiChildCtrl.Binding as BindingSource).DataSource as DataSet);
                        //DataTable childTable = childDataSet.Tables[guiChildCtrl.XmlAttributes["_LocalDataSetTableName"]];
                        //DataTable table = (this.binding.DataSource as DataSet).Tables[connectionConfig.ViewName];
                        //DataColumn dc =  table.Columns[mainControl.XmlAttributes["XMLAttribute"]];
                        //DataRow dr = table.Rows[0];
                        //BindingSource bs = new BindingSource();
                        //childTable.DefaultView.RowFilter  = String.Format("{0}='{1}'", dep.DependentField, dr[dc]);
                        
                        //childTable = childTable.DefaultView.ToTable();
                        //bs.DataSource = binding.DataSource;
                        //bs.DataMember = childTable.TableName;
                        //guiChildCtrl.Binding = bs;
                    }
                }
            }
        }

        private bool parseGlobalConfigs(XElement configSection)
        {
            try
            {
                if (configSection == null)
                    throw new Exception(Resources.GetString("{0} not found", ConfigConstants.Configs));

                // parse configs and check correctness 
                var cfgs = from el in configSection.Elements()
                           where (el.Name == "ViewCaption" ||
                                  el.Name == "ProcIU" ||
                                  el.Name == "XmlIU" ||
                                  el.Name == "ProcD")
                               && (el.Attribute("Name") != null)
                           select new { Key = el.Name.LocalName, Value = el.Attribute("Name").Value };

                // parse configs and assign to configs dictionary
                this.configs = cfgs.ToDictionary(el => el.Key, el => el.Value);
            }
            catch (Exception ex)
            {
                ex.LogError("76B2ED7D-AC98-4A06-9C95-5502F688BD06");
                throw;
            }

            return true;

        }

        private bool buildVisualFormAndPrototype(XElement editModuleSection)
        {
            try
            {
                if (editModuleSection == null)
                    throw new Exception(Resources.GetString("{0} not found", ConfigConstants.EditModule));

                // build visual presentation
                var controls = editModuleSection.Element(ConfigConstants.Controls);
                // check if root controls section exist
                if (controls == null)
                    throw new Exception(Resources.GetString("{0} not found", ConfigConstants.Controls));

                // create root visual control - "GroupBox"
                rootGui = GuiBuilder.CurrentFactory.CreateGroupBox();
                // root control need to fill parent form
                rootGui.Dock = DockStyle.Fill;
                // try to add current root control to form
                GuiBuilder.CurrentFactory.AddGuiToVisual(rootGui, this.scMain);
                // build visual presentation
                translateXmlToControl(controls, rootGui);

                // create object prototype
                this.prototype = new ObjectPrototype(controls, this.connectionConfig.ViewName);

                return true;
            }
            catch(Exception ex)
            {
                 ex.LogError("72DD5E39-D6EA-4788-96A7-B275F25DF5CF");
                 throw;
            }
        }

        private void parseEditModuleFormConfigs(XElement editFormSection)
        {
            try
            {
                if (editFormSection == null)
                    return;
                var formConfigsSection = editFormSection.Element(ConfigConstants.Configs);
                if ((formConfigsSection != null) && (formConfigsSection.HasElements))
                {
                    var frmConfigurations = from el in formConfigsSection.Elements()
                                            where (!el.IsEmpty) && (!el.HasElements)
                                            select new KeyValuePair<string, string>(el.Name.LocalName, el.Value);
                    applyFormConfigs(frmConfigurations);
                }
            }
            catch(Exception ex)
            {
                ex.LogError("A54BF1C4-28D2-427C-B483-0A2616E58918");
                throw;
            }
        }

        private void applyFormConfigs(IEnumerable<KeyValuePair<string, string>> frmConfigurations)
        {
            try
            {

                foreach (var el in frmConfigurations)
                {
                    switch (el.Key)
                    {
                        case "Text":
                            this.Text = el.Value;
                            break;
                        case "Width":
                            int width;
                            if (int.TryParse(el.Value, out width))
                                this.Width = width;
                            break;
                        case "Height":
                            int height;
                            if (int.TryParse(el.Value, out height))
                                this.Width = height;
                            break;
                        case "StartPosition":
                            FormStartPosition startPosition;
                            if (Enum.TryParse<FormStartPosition>(el.Value, out startPosition))
                                this.StartPosition = startPosition;
                            break;
                        case "WindowState":
                            FormWindowState winState;
                            if (Enum.TryParse<FormWindowState>(el.Value, out winState))
                                this.WindowState = winState;
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                ex.LogError("7156881A-F88F-4DF0-90B0-4CE42DDB0837");
                throw;
            }
        }


        private void translateXmlToControl(XElement rootElement, GuiControl parent)
        {
            try
            {

                // procesing all controls
                foreach (var childElement in rootElement.Elements())
                {
                    GuiControl cntrl = GuiBuilder.CurrentFactory.CreateGuiControl(
                                            childElement.Name.LocalName,
                                            parent
                                            );
                    // if control exist in available editmodule controls
                    if (cntrl != null)
                    {
                        // properties processing
                        cntrl.TabIndex = EditForm.NextTabIndex;
                        XElement properties = childElement.Element(ConfigConstants.Properties);
                        if (properties != null)
                        {
                            properties.Elements().ApplyPropertiesToControl(cntrl);
                            if (cntrl.XmlAttributes.ContainsKey("Name"))
                                namedControls.Add(cntrl.Name, cntrl);
                            if (cntrl is IDatasourceObject)
                                dataSourceControls.Add(cntrl.Name, cntrl);
                            string editable;
                            if (cntrl.XmlAttributes.TryGetValue("IsEditable", out editable) && Convert.ToBoolean(editable))
                                cntrl = GuiBuilder.CurrentFactory.CreateDictionaryDecorator(cntrl);
                        }

                        cntrl.OnCustomEvent += new EventHandler(cntrlCustomEvent);

                        parent.Add(cntrl);

                        var childChildControls = childElement
                                                .Element(ConfigConstants.Controls);
                        if (childChildControls != null)
                            translateXmlToControl(childChildControls, cntrl);
                    }
                }
            }
            catch (Exception ex)
            {
                ex.LogError("AE639C40-B928-4BAF-B5A0-1CBE14E5DEE1");
                throw;
            }
        }

        private void cntrlCustomEvent(object sender, EventArgs e)
        {
            try
            {
                //TODO: resolve circular dependency 
                if((e is DictClickEventArgs)&&(infoModule!=null))
                {
                    infoModule.Show((e as DictClickEventArgs).dictionaryViewName, connectionConfig);
                }

            }
            catch (Exception ex)
            {
#if	MAT
                EventAppLogger.WriteAppError(ex.LogError("9C31DD4A-735F-473E-8A31-2DE44E11AFCF"),connectionConfig.ConnectionString);
#endif
                MessageBox.Show(ex.Message, ex.GetType().ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private bool fillForm()
        {
            try
            {
                // using visitor pattern to fill the form with data
                rootGui.Accept(this.GuiVisitor);
                return true;
            }
            catch (Exception ex)
            {
                ex.LogError("D9E84A2C-49FF-4C9D-A5D6-3E6A0A5D5459");
                throw;
            }
            
        }
        private bool processData()
        {
            try
            {
                Dictionary<string, object> collectedData = this.CurrentData;

                if (collectedData.Count > 0)
                {
                    List<Parameter> procParams = new List<Parameter>();
                    switch (this.EditMode)
                    {
                        case (EditFormMode.Insert):
                            procParams.Add(new Parameter()
                            {
                                Key = "@TM",
                                Value = "0"
                            });
                            procParams.Add(new Parameter()
                            {
                                Key = "@ID",
                                Value = null
                            });
                            break;
                        case (EditFormMode.Copy):
                            procParams.Add(new Parameter()
                            {
                                Key = "@TM",
                                Value = "0"
                            });

                            procParams.Add(new Parameter()
                            {
                                Key = "@ID",
                                Value = id
                            });
                            break;
                        case (EditFormMode.Update):
                            procParams.Add(new Parameter()
                            {
                                Key = "@TM",
                                Value = "1"
                            });

                            procParams.Add(new Parameter()
                            {
                                Key = "@ID",
                                Value = id
                            });
                            break;
                    }

                    procParams.Add(new Parameter()
                    {
                        Key = "@DATA",
                        Value = collectedData.ConvertToProcedureData()
                    });

                    // ADD build xml and sent proc request
                    SqlParameterCollection procResult =
                        Model.GetProcResult(connectionConfig,
                                        this.configs["ProcIU"], procParams.ToArray());
                    // If execution completed with success
                    if (procResult != null)
                    {
                        foreach (SqlParameter curParam in procResult)
                        {

                            if (((curParam.Direction == ParameterDirection.InputOutput)
                                || ((curParam.Direction == ParameterDirection.Output)))
                                && (curParam.ParameterName.Equals("@ID")))
                            {
                                this.id = curParam.Value.ToString();
                                return true;
                            }
                        }
                    }
                }
                return false;
            }
            catch (Exception ex)
            {
                ex.LogError("7B65A41F-B12F-4E5D-BCC1-9BBE1AAF87EE");
                throw;
            }
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            try
            {

                if (!IsMeetRequirements())
                {
                    MessageBox.Show(Resources.GetString("Please, Fill all required fields."));
                    return;
                }

                if (!this.processData())
                    throw new Exception(Resources.GetString("Error while sending the data."));
                else
                    this.DialogResult = DialogResult.OK;
            }
            catch (Exception ex)
            {
#if MAT
                 EventAppLogger.WriteAppError(ex.LogError("1F504DF4-042B-454A-852F-6F15C805DB78"),connectionConfig.ConnectionString);
#endif
                 MessageBox.Show(ex.Message, ex.GetType().ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private bool IsMeetRequirements()
        {
            if (currentValidator == null)
                currentValidator = new EditFormIsValidVisitor();
            else
                // drop to default
                currentValidator.IsMeetRequirements = true;

            rootGui.Accept(currentValidator);
            return currentValidator.IsMeetRequirements;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
        }

        private void EditForm_Load(object sender, EventArgs e)
        {
            btnOk.Enabled=fillForm();
        }
    }
    public static class EditModuleExtension
    {
        public static string Dump(this Dictionary<string, object> data)
        {
            var sb = new StringBuilder("Dumped data:\r\n");
            foreach(var item in data)
            {
                sb.AppendFormat("{0}: {1}\r\n",item.Key,item.Value);
            }
            return sb.ToString();
        }
        // convert dictionary with object attributes to procedure xml @DATA parameter
        public static string ConvertToProcedureData(this Dictionary<string, object> data)
        {
            /*
             *   <ROOT>
	         *      <ROW	Attr1="Value" 
			 *              Attr2="Value" 
			 *              Attr3="Value" 
			 *              Attr4="Value" 
             *              />
             *  </ROOT>
             * 
             */
            var datas = data.Select(el=>
                            {
                                if (el.Value is XElement)
                                    return (XObject)new XElement("Complex", el.Value, new XAttribute("FieldName", el.Key));
                                else if(el.Value == null)
                                    return (XObject)new XAttribute(el.Key, String.Empty);
                                else if(el.Value is byte[])
                                    return (XObject)new XAttribute(el.Key, Convert.ToBase64String(el.Value as byte[]));
                                else
                                    return (XObject)new XAttribute(el.Key, el.Value);                        
                            });

            XDocument result = new XDocument(
                    new XDeclaration("1.0", "utf-16", "yes"),
                    new XElement("ROOT",
                            new XElement("ROW", datas
                                )
                        )
                );
            return result.ToString();
        }

        public static void ApplyPropertiesToControl(this IEnumerable<XElement> properties, GuiControl cntrl)
        {
            try
            {
                var valueProperties = properties.Where(el => (!el.IsEmpty) && (!el.HasElements));

                // apply to control
                foreach (var prop in valueProperties)
                    cntrl.SetPropertyValue(prop.Name.LocalName, prop.Value);
                var processStaticItems = true;
                if (cntrl is IDatasourceObject)
                {
                    /* select all datasource elements only if datasource not empty 
                     * and sourcecipher exist and not empty
                     * and fields exist
                     * and key field exist
                     */

                    var dataSources = properties.Where(el => el.HasElements
                                                && (el.Name.LocalName == "Datasource"));

                    // if dataSourceAttrubes was found do not process static section
                    // and process datasource elements
                    if (dataSources.Any())
                    {
                        processStaticItems = false;
                    
                                            
                        // find value elements
                        var valueElements = dataSources.Elements().Where(el => !el.HasElements)
                                                    .Select(element => new { 
                                                                            Name = element.Name.LocalName, 
                                                                            Value = element.Value 
                                                                            });

                        // add all value elements values to control properties
                        foreach (var element in valueElements)
                            cntrl.SetPropertyValue(element.Name, element.Value);

                        // lookup for fields in datasource section
                        var fieldsElements = dataSources.Elements("Fields")
                                                .Elements()
                                                .Where(field =>(!field.IsEmpty)
                                                              &&(!field.HasElements));

                        var keyField = fieldsElements.FirstOrDefault(field => field.Name.LocalName == "Key");
                        if (keyField != null)
                            cntrl.SetPropertyValue("_KeyField", keyField.Value);
                        else
                            throw new NullReferenceException(Resources.GetString("Key field not found in Datasource"));

                        var parentKeyField = fieldsElements.FirstOrDefault(field => field.Name.LocalName == "ParentKey");
                        if (parentKeyField != null)// for treeView
                            cntrl.SetPropertyValue("_ParentKeyField", parentKeyField.Value);

                        // select all fields to strings array
                        string fields = fieldsElements
                                        .Select(el => el.Value)
                                        .Aggregate((u1, u2) => u1 + "," + u2);
                        // select sort fields
                        var sortFields = fieldsElements.Where(el => el.Attribute("Sort") != null);
                        if (sortFields.Any())
                        {
                            // build sorts for dataview sort propertie
                            var sorts =     from fld in sortFields
                                            where fld.Attribute("Sort").Value == "asc"
                                                    || fld.Attribute("Sort").Value == "desc"
                                            select fld.Value+" "+fld.Attribute("Sort").Value.ToUpper();
                            if(sorts.Any()){
                                string tmp = sorts.Aggregate((u1, u2) => u1+", "+u2);
                                cntrl.SetPropertyValue("_Sorts", tmp);
                            }
                                       
                                      

                            // select sorted fields to string
                            var sortAscFields = from fld in sortFields
                                                where fld.Attribute("Sort").Value == "asc"
                                                select fld.Value;
                            if(sortAscFields.Any())
                            {
                                string tmp = sortAscFields.Aggregate((u1, u2) => u1 + "," + u2);
                                cntrl.SetPropertyValue("_SortAscFields", tmp);
                            }

                            var sortDescFields = from fld in sortFields
                                                    where fld.Attribute("Sort").Value == "desc"
                                                    select fld.Value;
                            if(sortDescFields.Any())
                            {
                                string tmp = sortDescFields.Aggregate((u1, u2) => u1 + "," + u2);
                                cntrl.SetPropertyValue("_SortDescFields", tmp);
                            }
                        }
                        //add key field to GuiControl
                        cntrl.SetPropertyValue("_Fields", fields);
                    }
                }

                if (processStaticItems && (cntrl is IStaticItemsContainer))
                {
                    // lookup for data properties
                    var staticItems = properties.Where(el => (el.HasElements) && (el.Name.LocalName.Equals("StaticItems")))
                                        .Elements("Value")
                                        .Where(el => !el.HasElements)
                                        .Select(el => el.Value.ToString());

                    staticItems.ProcessStaticItems((IStaticItemsContainer)cntrl);
                }

            }
            catch (Exception ex)
            {
                ex.LogError("7B65A41F-B12F-4E5D-BCC1-9BBE1AAF87EE");
                throw;
            }
            
        }
        public static void ProcessStaticItems(this IEnumerable<String> items, IStaticItemsContainer cntrl)
        {
            foreach (var item in items)
                cntrl.AddStaticItem(item);
        }
    }

    // constant xml elements names for Views Configuration XML
    internal static class ConfigConstants
    {

        #region XMLElementsNames
        public static string AppName = "EditModule";
        public static string Root = "root";
        public static string Properties = "Properties";
        public static string Configs = "Configs";
        public static string Controls = "Controls";
        public static string EditModule = "EditModule";
        public static string NameOrig = "NameOrig";
        public static string FormConfigs = "Configs";
        public static string Dependencies = "Dependencies";
        #endregion
    }
}
